/*
 * OrganismEditorPanel.java
 *
 * Created on January 29, 2008, 4:16 PM
 *
 * @author  Ryan J. Bovorasmy.com
 * 
 * @history 2-5-2008 - Paul Kratt - Added ?
 */
package protovitae.ui;

import com.sun.org.apache.xml.internal.serialize.XMLSerializer;
import java.awt.Color;
import java.io.File;
import java.io.FileWriter;
import javax.swing.DefaultListModel;
import javax.swing.JColorChooser;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import protovitae.data.ConcreteGene;
import protovitae.data.ConcreteOrganism;
import protovitae.data.Gene;
import protovitae.data.OrganismTree;

public class OrganismEditorPanel extends javax.swing.JPanel {

    private MainWindow parent = null;
    private DefaultListModel activetraits = new DefaultListModel();
    private ConcreteOrganism editing; //The organism this editor is editing. Why it's here: We can spawn the editor into a separate window.

    private TraitEditorPanel traitpanel = null; //A trait editor panel "connected" to this organism editor. If one exists, editing will spawn there.

    private OrganismTree treemodel;

    /** Creates new form OrganismEditorPanel */
    public OrganismEditorPanel(MainWindow parent) {
        this.parent = parent;
        initComponents();
        setEdit(parent.getSelectedOrganism());
    }

    /*** Call this after simulation has been initialized.
     * We can't do it in the constructor because the simulation doesn't exist at that time.
     */
    public void initTree() {
        treemodel = new OrganismTree(parent.getSimulation().getMasterlist());
        treAvailable.setModel(treemodel);
        treemodel.reload();
    }

    /** Call this function when an organism is added. It's purpose is to update the tree listing all traits **/
    public void updateTraitTree() {
        treemodel.reload();
    }

    /** Set the organism this editor is editing.
     * @param editing The origanism
     */
    public void setEdit(ConcreteOrganism editing) {
        this.editing = editing;
        activetraits.clear();
        if (editing != null) {
            for (Gene gene : editing.getGenome()) {
                activetraits.addElement(gene);
            //Update button color
            }
            btnColor.setBackground(editing.getColor());
            btnColor.setForeground(new Color(editing.getColor().getRGB() ^ 0xFFFFFF));
        }
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        mnuActiveTrait = new javax.swing.JPopupMenu();
        mnuActiveEdit = new javax.swing.JMenuItem();
        mnuAvailableTrait = new javax.swing.JPopupMenu();
        mnuAvailableImport = new javax.swing.JMenuItem();
        mnuAvailableExport = new javax.swing.JMenuItem();
        barOrganismTools = new javax.swing.JToolBar();
        btnNewTrait = new javax.swing.JButton();
        btnEditTrait = new javax.swing.JButton();
        btnAddToActive = new javax.swing.JButton();
        btnRemoveFromActive = new javax.swing.JButton();
        btnColor = new javax.swing.JButton();
        btnUpdateList = new javax.swing.JButton();
        jspTraitSplit = new javax.swing.JSplitPane();
        pnlActiveTraits = new javax.swing.JPanel();
        lblActive = new javax.swing.JLabel();
        scrActive = new javax.swing.JScrollPane();
        lstActive = new javax.swing.JList();
        pnlMasterTraits = new javax.swing.JPanel();
        lblAvailable = new javax.swing.JLabel();
        scrAvailable = new javax.swing.JScrollPane();
        treAvailable = new javax.swing.JTree();

        mnuActiveEdit.setText("Edit Selected Trait");
        mnuActiveEdit.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                mnuActiveEditActionPerformed(evt);
            }
        });
        mnuActiveTrait.add(mnuActiveEdit);

        mnuAvailableImport.setText("Import Gene from file...");
        mnuAvailableImport.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                mnuAvailableImportActionPerformed(evt);
            }
        });
        mnuAvailableTrait.add(mnuAvailableImport);

        mnuAvailableExport.setText("Export gene to file...");
        mnuAvailableExport.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                mnuAvailableExportActionPerformed(evt);
            }
        });
        mnuAvailableTrait.add(mnuAvailableExport);

        setLayout(new java.awt.BorderLayout());

        barOrganismTools.setRollover(true);

        btnNewTrait.setText("New Trait");
        btnNewTrait.setFocusable(false);
        btnNewTrait.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        btnNewTrait.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        btnNewTrait.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnNewTraitActionPerformed(evt);
            }
        });
        barOrganismTools.add(btnNewTrait);

        btnEditTrait.setText("Edit trait");
        btnEditTrait.setFocusable(false);
        btnEditTrait.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        btnEditTrait.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        btnEditTrait.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnEditTraitActionPerformed(evt);
            }
        });
        barOrganismTools.add(btnEditTrait);

        btnAddToActive.setText("Add selected trait");
        btnAddToActive.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnAddToActiveActionPerformed(evt);
            }
        });
        barOrganismTools.add(btnAddToActive);

        btnRemoveFromActive.setText("Remove selected trait");
        btnRemoveFromActive.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnRemoveFromActiveActionPerformed(evt);
            }
        });
        barOrganismTools.add(btnRemoveFromActive);

        btnColor.setText("Set organism color");
        btnColor.setFocusable(false);
        btnColor.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        btnColor.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        btnColor.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnColorActionPerformed(evt);
            }
        });
        barOrganismTools.add(btnColor);

        btnUpdateList.setText("Update list");
        btnUpdateList.setFocusable(false);
        btnUpdateList.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        btnUpdateList.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        btnUpdateList.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnUpdateListActionPerformed(evt);
            }
        });
        barOrganismTools.add(btnUpdateList);

        add(barOrganismTools, java.awt.BorderLayout.NORTH);

        jspTraitSplit.setDividerLocation(300);

        pnlActiveTraits.setLayout(new java.awt.BorderLayout());

        lblActive.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        lblActive.setText("Active Traits");
        pnlActiveTraits.add(lblActive, java.awt.BorderLayout.NORTH);

        lstActive.setModel(activetraits);
        lstActive.setComponentPopupMenu(mnuActiveTrait);
        lstActive.addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyReleased(java.awt.event.KeyEvent evt) {
                lstActiveKeyReleased(evt);
            }
        });
        scrActive.setViewportView(lstActive);

        pnlActiveTraits.add(scrActive, java.awt.BorderLayout.CENTER);

        jspTraitSplit.setLeftComponent(pnlActiveTraits);

        pnlMasterTraits.setLayout(new java.awt.BorderLayout());

        lblAvailable.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        lblAvailable.setText("Available Traits");
        pnlMasterTraits.add(lblAvailable, java.awt.BorderLayout.NORTH);

        treAvailable.setComponentPopupMenu(mnuAvailableTrait);
        treAvailable.setModel(null);
        scrAvailable.setViewportView(treAvailable);

        pnlMasterTraits.add(scrAvailable, java.awt.BorderLayout.CENTER);

        jspTraitSplit.setRightComponent(pnlMasterTraits);

        add(jspTraitSplit, java.awt.BorderLayout.CENTER);
    }// </editor-fold>//GEN-END:initComponents

    private void btnAddToActiveActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnAddToActiveActionPerformed
        Object selected=null;
        if(treAvailable.getSelectionPath() != null)
            selected = treAvailable.getSelectionPath().getLastPathComponent();

        if (selected != null && selected instanceof ConcreteGene) {
            ConcreteGene thecopy = new ConcreteGene((ConcreteGene) selected, editing);
            editing.addGene(thecopy);
            activetraits.addElement(thecopy); //Add to the list inside the window

            updateTraitTree();
        } else {
            JOptionPane.showMessageDialog(this, "Select a gene to copy from the list on the right.");
        }
    }//GEN-LAST:event_btnAddToActiveActionPerformed

    private void btnRemoveFromActiveActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnRemoveFromActiveActionPerformed
        Object[] selitems = lstActive.getSelectedValues();

        //Remove selected traits from the organism.
        for (int i = 0; i < selitems.length; i++) {
            activetraits.removeElement(selitems[i]);
            editing.getGenome().remove(selitems[i]);
        }
    }//GEN-LAST:event_btnRemoveFromActiveActionPerformed

    private void mnuActiveEditActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_mnuActiveEditActionPerformed
        //Check active.
        //We have two separate right-click menus in case we ever want to make one of them different.

        if (lstActive.getSelectedIndex() >= 0) {
            if (traitpanel != null) {
                ConcreteGene selectedgene = (ConcreteGene) activetraits.get(lstActive.getSelectedIndex());

                traitpanel.setEdit(selectedgene);
                parent.switchTab(traitpanel); //Switch to the tab for ease of use.

            } else {
                TraitEditorFrame editme = new TraitEditorFrame(parent);
                ConcreteGene selectedgene = (ConcreteGene) activetraits.get(lstActive.getSelectedIndex());

                editme.getPanel().setEdit(selectedgene);
                editme.setVisible(true);
            }
        }
}//GEN-LAST:event_mnuActiveEditActionPerformed

    private void mnuAvailableImportActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_mnuAvailableImportActionPerformed
        JFileChooser fbox = new JFileChooser();
        
        fbox.setFileFilter(new FileXMLFilter());
        if(fbox.showOpenDialog(this)==JFileChooser.APPROVE_OPTION){
            try{
                DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
                DocumentBuilder loader = factory.newDocumentBuilder();
                Document loadDocument = loader.parse(fbox.getSelectedFile());
                
                NodeList docnodes = loadDocument.getChildNodes();
                if(docnodes.item(0).getNodeName().equals("protovitae_gene")){
                    ConcreteGene geneX = new ConcreteGene(null);
                    geneX.load((Element)docnodes.item(0));
                    parent.getSimulation().getMasterlist().addStockTrait(geneX);
                    updateTraitTree();
                }
            }
            catch(Exception e){
                e.printStackTrace();
            }
        }
}//GEN-LAST:event_mnuAvailableImportActionPerformed

    private void btnColorActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnColorActionPerformed
        if (editing != null) {
            Color temp = JColorChooser.showDialog(this, "Select new organism color", editing.getColor());

            if (temp != null) {
                editing.setColor(temp);
                btnColor.setBackground(temp);
                btnColor.setForeground(new Color(temp.getRGB() ^ 0xFFFFFF));
            }
        }
    }//GEN-LAST:event_btnColorActionPerformed

    private void btnNewTraitActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnNewTraitActionPerformed
        //Create a new trait and add it to the current organism.
        String retval = JOptionPane.showInputDialog("Enter a name for the new trait:");
        if (retval != null) {
            ConcreteGene temp1 = new ConcreteGene(editing);
            temp1.setName(retval);
            editing.addGene(temp1);
            activetraits.addElement(temp1);
        //To do: Add a copy to the master list?
        }
    }//GEN-LAST:event_btnNewTraitActionPerformed

    /** Edit a trait from the active list. **/
    private void btnEditTraitActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnEditTraitActionPerformed
        mnuActiveEditActionPerformed(null);
    //Invoke the code in the right click menu that does the same thing.
}//GEN-LAST:event_btnEditTraitActionPerformed

    private void btnUpdateListActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnUpdateListActionPerformed
        this.updateTraitTree();
    }//GEN-LAST:event_btnUpdateListActionPerformed

private void mnuAvailableExportActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_mnuAvailableExportActionPerformed
    JFileChooser fbox = new JFileChooser();
    Object gene = null;
    if(treAvailable.getSelectionPath()!=null)
        gene = treAvailable.getSelectionPath().getLastPathComponent();

    fbox.setFileFilter(new FileXMLFilter());
    if (gene instanceof ConcreteGene) {
        if (fbox.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) {
            try {
                //Create initial XML Document and root element
                DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
                DocumentBuilder loader = factory.newDocumentBuilder();
                Document saveDocument = loader.newDocument();
                Element root = saveDocument.createElement("protovitae_gene");

                ((ConcreteGene) (gene)).save(root, saveDocument);
                saveDocument.appendChild(root);

                //Go save!
                XMLSerializer serializer = new XMLSerializer();
                if(!fbox.getSelectedFile().getAbsolutePath().toLowerCase().endsWith(".xml"))
                    fbox.setSelectedFile(new File(fbox.getSelectedFile().getAbsolutePath().concat(".xml")));
                FileWriter fw = new FileWriter(fbox.getSelectedFile());
                serializer.setOutputCharStream(fw);
                serializer.serialize(saveDocument);

                serializer.endDocument();
                fw.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    } else {
        JOptionPane.showMessageDialog(this, "Nothing exported. Select a gene first.");
    }
}//GEN-LAST:event_mnuAvailableExportActionPerformed

private void lstActiveKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_lstActiveKeyReleased
    if(evt.getKeyCode()==evt.VK_DELETE){
        btnRemoveFromActiveActionPerformed(null);
    }
}//GEN-LAST:event_lstActiveKeyReleased

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JToolBar barOrganismTools;
    private javax.swing.JButton btnAddToActive;
    private javax.swing.JButton btnColor;
    private javax.swing.JButton btnEditTrait;
    private javax.swing.JButton btnNewTrait;
    private javax.swing.JButton btnRemoveFromActive;
    private javax.swing.JButton btnUpdateList;
    private javax.swing.JSplitPane jspTraitSplit;
    private javax.swing.JLabel lblActive;
    private javax.swing.JLabel lblAvailable;
    private javax.swing.JList lstActive;
    private javax.swing.JMenuItem mnuActiveEdit;
    private javax.swing.JPopupMenu mnuActiveTrait;
    private javax.swing.JMenuItem mnuAvailableExport;
    private javax.swing.JMenuItem mnuAvailableImport;
    private javax.swing.JPopupMenu mnuAvailableTrait;
    private javax.swing.JPanel pnlActiveTraits;
    private javax.swing.JPanel pnlMasterTraits;
    private javax.swing.JScrollPane scrActive;
    private javax.swing.JScrollPane scrAvailable;
    private javax.swing.JTree treAvailable;
    // End of variables declaration//GEN-END:variables

    /** Retrieve the organism this panel is currently editing **/
    public ConcreteOrganism getEditing() {
        return editing;
    }

    /** Set the trait editor panel linked to this organism editor, if any **/
    public void setTraitpanel(TraitEditorPanel traitpanel) {
        this.traitpanel = traitpanel;
    }
}
